<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<script src="../vue.js"></script>
		<title>Prop</title>
		<!-- https://v2.cn.vuejs.org/v2/guide/components-props.html  -->
	</head>
	<body>
		<div id="post">
			<!-- <blog-post post-title="hello!"></blog-post> -->
			<blog-post title="My journey with Vue"></blog-post>

			<!-- 动态赋予一个变量的值 -->
			<blog-post v-bind:title="title2"></blog-post>

			<!-- 动态赋予一个复杂表达式的值 -->
			<blog-post v-bind:title="title + ' by ' + author.name"></blog-post>
			<!-- 在上述两个示例中，我们传入的值都是字符串类型的，但实际上任何类型的值都可以传给一个 prop。 -->

			<!-- 传入一个数字 -->
			<!-- 即便 `42` 是静态的，我们仍然需要 `v-bind` 来告诉 Vue -->
			<!-- 这是一个 JavaScript 表达式而不是一个字符串。-->
			<blog-post v-bind:likes="42"></blog-post>

			<!-- 用一个变量进行动态赋值。-->
			<blog-post v-bind:likes="likes"></blog-post>

			<!-- 传入一个布尔值 -->
			<!-- 包含该 prop 没有值的情况在内，都意味着 `true`。-->
			<blog-post is-published></blog-post>

			<!-- 即便 `false` 是静态的，我们仍然需要 `v-bind` 来告诉 Vue -->
			<!-- 这是一个 JavaScript 表达式而不是一个字符串。-->
			<blog-post v-bind:is-published="false"></blog-post>

			<!-- 用一个变量进行动态赋值。-->
			<blog-post v-bind:is-published="isPublished"></blog-post>

			<!-- 传入一个数组 -->
			<!-- 即便数组是静态的，我们仍然需要 `v-bind` 来告诉 Vue -->
			<!-- 这是一个 JavaScript 表达式而不是一个字符串。-->
			<blog-post v-bind:comment-ids="[234, 266, 273]"></blog-post>

			<!-- 用一个变量进行动态赋值。-->
			<blog-post v-bind:comment-ids="commentIds"></blog-post>


			<!-- 传入一个对象 -->
			<!-- 即便对象是静态的，我们仍然需要 `v-bind` 来告诉 Vue -->
			<!-- 这是一个 JavaScript 表达式而不是一个字符串。-->
			<blog-post v-bind:author="{
			    name: 'Veronica',
			    company: 'Veridian Dynamics'
			  }"></blog-post>

			<!-- 用一个变量进行动态赋值。-->
			<blog-post v-bind:author="author"></blog-post>


			<!-- 
				传入一个对象的所有 property
				如果你想要将一个对象的所有 property 都作为 prop 传入，你可以使用不带参数的 v-bind (取代 v-bind:prop-name)。例如，对于一个给定的对象 post：
			 -->
			<blog-post v-bind="postObj"></blog-post>
			<!-- 等价于 -->
			<blog-post v-bind:title="postObj.title" v-bind:likes="postObj.likes" v-bind:comment-ids="postObj.commentIds"
				v-bind:author="postObj.author"></blog-post>

			<!-- 单向数据流 -->
			<blog-post2 v-bind:initial-counter="6"></blog-post2>
			<blog-post3 size="AbC"></blog-post3>

			<!-- Prop 验证  -->
			<my-component v-bind:prop-a="66" v-bind:prop-b="propB" v-bind:prop-c="propC" v-bind:prop-d="200"
				v-bind:prop-e="propEValue" v-bind:prop-f="propF"></my-component>

			<!-- 类型检查 -->
			<blog-post4 v-bind:author="person"></blog-post4>
			
			<!-- 禁用 Attribute 继承 
			
			这个模式允许你在使用基础组件的时候更像是使用原始的 HTML 元素，而不会担心哪个元素是真正的根元素：
			-->
			<base-input label="姓名: " value='国龙'></base-input>
			</br>
			<base-input
			  label="Username:"
			  v-model="username"
			  required
			  placeholder="Enter your username"
			></base-input>
		</div>

	</body>
	<script>
		/**
		 HTML 中的 attribute 名是大小写不敏感的，所以浏览器会把所有大写字符解释为小写字符。
		 这意味着当你使用 DOM 中的模板时，camelCase (驼峰命名法) 的 prop 名需要使用其等价的 kebab-case (短横线分隔命名) 命名：
		 */
		// Vue.component('blog-post', {
		// 	// 在 JavaScript 中是 camelCase 的
		// 	props: ['title'],
		// 	template: '<h1>{{title}}</h1>'
		// })

		// Prop 类型
		//到这里，我们只看到了以字符串数组形式列出的 prop：
		// props: ['title', 'likes', 'isPublished', 'commentIds', 'author']
		//但是，通常你希望每个 prop 都有指定的值类型。这时，你可以以对象形式列出 prop，这些 property 的名称和值分别是 prop 各自的名称和类型：


		/**
		 这不仅为你的组件提供了文档，还会在它们遇到错误的类型时从浏览器的 JavaScript 控制台提示用户。
		 你会在这个页面接下来的部分看到类型检查和其它 prop 验证
		 */

		// 传递静态或动态 Prop
		// 像这样，你已经知道了可以像这样给 prop 传入一个静态的值：
		//<blog-post title="My journey with Vue"></blog-post>
		Vue.component('blog-post', {
			props: {
				title: String,
				likes: Number,
				isPublished: Boolean,
				commentIds: Array,
				author: Object,
				callback: Function,
				contactsPromise: Promise // or any other constructor
			},
			template: '<div><h1>{{title}}</h1>{{likes}}{{commentIds}}{{author}}</div>'
		})

		// 单向数据流
		// 1. 这个 prop 用来传递一个初始值；这个子组件接下来希望将其作为一个本地的 prop 数据来使用。
		// 在这种情况下，最好定义一个本地的 data property 并将这个 prop 用作其初始值：
		Vue.component('blog-post2', {
			// 在 JavaScript 中是 camelCase 的
			props: ['initialCounter'],
			data: function() {
				return {
					counter: this.initialCounter
				}
			},
			template: '<h1>{{counter}}</h1>'
		})

		//2. 这个 prop 以一种原始的值传入且需要进行转换。在这种情况下，最好使用这个 prop 的值来定义一个计算属性：
		Vue.component('blog-post3', {
			props: ['size'],
			computed: {
				normalizedSize: function() {
					return this.size.trim().toLowerCase()
				}
			},
			template: '<h1>{{normalizedSize}}</h1>'
		})

		// Prop 验证
		Vue.component('my-component', {
			props: {
				// 基础的类型检查 (`null` 和 `undefined` 会通过任何类型验证)
				propA: Number,
				// 多个可能的类型, 字符串或者数字，类型二选一
				propB: [String, Number],
				// 必填的字符串
				propC: {
					type: String,
					required: true
				},
				// 带有默认值的数字
				propD: {
					type: Number,
					default: 100
				},
				// 带有默认值的对象
				propE: {
					type: Object,
					// 对象或数组默认值必须从一个工厂函数获取
					default: function() {
						return {
							message: 'hello'
						}
					}
				},
				// 自定义验证函数
				propF: {
					validator: function(value) {
						// 这个值必须匹配下列字符串中的一个
						return ['success', 'warning', 'danger'].includes(value)
					}
				}
			},
			template: '<div>propA = {{propA}}</br> propB = {{propB}}</br> propC = {{propC}}</br> propD ={{propD}}</br> propE ={{propE}}</br>  propF ={{propF}} </div>'
		})

		// 类型检查
		// ES5 
		// function Person (firstName, lastName) {
		//   this.firstName = firstName
		//   this.lastName = lastName
		// }
		// ES6
		class Person{
			constructor(firstName, lastName){
				this.firstName = firstName;
				this.lastName = firstName;
			}
		}
		Vue.component('blog-post4', {
			props: {
				// 来验证 author prop 的值是否是通过 new Person 创建的
				author: Person
			},
			template: '<div>{{author}}</div>'
		})
		
		// 禁用 Attribute 继承
		Vue.component('base-input', {
		  inheritAttrs: false,
		  props: ['label', 'value'],
		  template: `
		    <label>
		      {{ label }}
		      <input
		        v-bind="$attrs"
		        v-bind:value="value"
		        v-on:input="$emit('input', $event.target.value)"
		      >
		    </label>
		  `
		})

		var data = {
			title: 'prop',
			title2: 'hello world',
			author: {
				name: 'test'
			},
			likes: 26,
			isPublished: true,
			commentIds: [12, 23, 45],
			postObj: {
				title: '传入一个对象的所有 property',
				author: {
					name: '对象的所有 property'
				},
				likes: 28,
				isPublished: true,
				commentIds: [22, 33, 55],
			},
			propB: 'hello world',
			propC: 'WORLD',
			propEValue: {
				name: '国龙',
				age: 40
			},
			propF: 'success',
			person: Person = new Person('你好','世界'),
			username:''

		}
		var vm1 = new Vue({
			el: '#post',
			data: data,
		})
	</script>
</html>